<?php
/*
Cogumelo v0.2 - Innoto S.L.
Copyright (C) 2010 Innoto Gestión para el Desarrollo Social S.L. <mapinfo@map-experience.com>

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
USA.
*/

class CogumeloCore extends Singleton
{
	public static $url_patterns;
	
	public static $debug_message;
	
	public $errorControl;
	public $logControl;
	
	protected static $load_completed = false;
	
	protected function __construct()
	{
		Cogumelo::Load('ErrorControllerFactory');
		Cogumelo::Load('LogControllerFactory');
		
		$this->logControl = LogControllerFactory::getLogController();
		$this->logControl->setAutodump(true);
		$this->errorControl = ErrorControllerFactory::getErrorController();
	}
	
	/*
	 * Returns the instance of Cogumelo
	 * 
	 * @return Object Cogumelo
	 */
	static function Recover()
	{
		return parent::getInstance('Cogumelo');
	}
	
	/*
	 * Starts a project
	 * 
	 * @param site_path (string)
	 *   Absolute path where the site is located 
	 */
	static function Start($site_path = SITE_PATH)
	{
		session_start();
		
		if(!file_exists($site_path))
			Cogumelo::Forbid("Cogumelo Error: Site path '$site_path' does not exist");
		
		// Require site setup & url patterns
		$a = require_once($site_path.'Conf/setup.inc');
		$b = require_once($site_path.'urls.inc');
		
		self::$load_completed = $a && $b;
		
		// Prepare to perform the request
		Cogumelo::Load("C_RequestManager");
		$uri = preg_replace('#^'.SITE_URI.'#', '', $_SERVER["REDIRECT_URL"], 1);
		
		// Call Access check for extended compatibility
		Cogumelo::AccessCheck($uri);
		
		// Perform a Request
		Cogumelo::Request($uri, Cogumelo::$url_patterns);
	}
	
	// Generic AccessCheck (for all requests)
	protected static function AccessCheck($requested_uri) {}
	
	// Loop & search for matches for $uri on $url_patterns
	static function Request($uri, $url_patterns)
	{
		$_SERVER["REDIRECT_STATUS"] = 404;
		header("HTTP/1.0 200 OK");
		foreach($url_patterns as $patt => $cmd)
		{
			// Capture pattern and group
			preg_match('#^(.*)(\$[0-9]+)?$#', $patt, $replace_params);
			$pattern = $replace_params[1];
			$group = ( isset($replace_params[2]) ) ? $replace_params[2] : '$1';
			
			// check if pattern match & replace $uri with user-wanted piece of it (group)
			// 	-1 means no limit, $count is passed by reference
			$kept_uri = preg_replace($pattern, $group, $uri, -1, $count);
			
			if ( is_null($count) ):
				Cogumelo::Error("An error has occurred when performing the request. pattern='$replace_params[1]'; group='$replace_params[2]'; uri='$uri';");	
			elseif($count > 0):
				// mantain full URI if no group is defined
				if( $kept_uri == '' && !preg_match('#[^\\\]\(#', $pattern) ) $kept_uri = $uri;
				
				if( is_array($cmd) )
					Cogumelo::Request($kept_uri, $cmd);
				else
					C_RequestManager::Request($kept_uri, $cmd);
			endif;
		}
		header("HTTP/1.0 404 Not Found");
		exit;
	}
	
	//
	// Special requests methods
	//
	
	// Redirect browser to given url and stop the script
	static function Redirect($redirect_url)
	{
		C_RequestManager::Redirect($redirect_url);
	}
	
	// Unauthorize a request & show error
	static function Unauthorize($debug_message = '')
	{
		Cogumelo::Log(__METHOD__."(): Stoped request '{$_SERVER["REDIRECT_URL"]}' with \$debug_message='{$debug_message}'", 2);
		
		self::EndRequest(401, $debug_message);
	}
	// Forbid a request & show error
	static function Forbid($debug_message = '')
	{
		Cogumelo::Log(__METHOD__."(): Stoped request '{$_SERVER["REDIRECT_URL"]}' with \$debug_message='{$debug_message}'", 2);
		
		self::EndRequest(403, $debug_message);
	}
	// show 404 error
	static function NotFound($debug_message = '')
	{
		self::EndRequest(404, $debug_message);
	}
	// show 505 internal server error
	static function ServerError($debug_message = '')
	{
		Cogumelo::Log(__METHOD__."(): Stoped request '{$_SERVER["REDIRECT_URL"]}' with \$debug_message='{$debug_message}'", 2);
		
		self::EndRequest(505, $debug_message);
	}
	// Generic end-request with http status code
	private static function EndRequest($status, $debug_message)
	{
		$_SERVER["REDIRECT_STATUS"] = $status;
		Cogumelo::$debug_message = (DEBUG) ? $debug_message : "";
		Cogumelo::View('Error.inc');
	}
	
	//
	//
	// SOURCE IMPORT TOOLS
	//
	//
	
	// Load a class
	static function Load($class)
	{
		return C_ClassLoader::Load($class);
	}
	
	// Include a View "on the fly"
	static function View($view_relative_path)
	{
		global $template, $tplFile;
		return include(SITE_PATH."Controllers/Views/{$view_relative_path}");
	}
	
	// capture a view result using the output buffer
	static function getView($view_relative_path)
	{
		ob_start();
		include(SITE_PATH."Controllers/Views/{$view_relative_path}");
		return ob_get_clean();
	}
	
	// Load a module
	static function LoadModule($m)
	{	
		// search for module's folder only under SITE_PATH
		$p = SITE_PATH;
		
		if( !file_exists("{$p}Modules/{$m}") )
			Cogumelo::Error("Module Path not found when loading '$m'; path=".$p."Modules/$m");
		
		$files = array(
			"{$p}Modules/{$m}/{$m}ClassLoader.inc",
			"{$p}Modules/{$m}/{$m}.inc"
		);
		$errors = array(
			"Module Class Loader not found for '$m' Module",
			"Module Core Class not found for '$m' Module"
		);
		
		// check & require files
		foreach($files as $k => $file)
		{
			if(!file_exists($file))
				Cogumelo::Error($errors[$k]);
			else
				require_once($file);
		}
	}
	

	
	//
	//
	// LOG & ERROR CONTROL
	//
	//
	static function Error($description, $error_code = 0)
	{
		// Check for system load completed to prevent ErrorLogController not-wanted errors
		if( self::$load_completed ):
			Cogumelo::Recover()->errorControl->raiseError($error_code, $description);
		else:
			echo "<pre>";
			Throw new exception("Cogumelo Error: '$description'. Error Code: $error_code");
		endif;
		
		if($error_code < 10) exit;
	}
	
	static function Log($description, $log_level)
	{
		// Check for system load completed to prevent LogController not-wanted errors
		if( self::$load_completed ):
			Cogumelo::Recover()->logControl->addLogLine($description, $log_level);
		else:
			echo "<pre>";
			trigger_error("Cogumelo Log: '$description'. Log_Level: $log_level");
		endif;
	}
}